package com.cskaoyan.wx.service;

import com.cskaoyan.bean.*;
import com.cskaoyan.bean.Comment;

import com.cskaoyan.mapper.*;
import com.cskaoyan.utils.UserUtils;
import com.cskaoyan.wx.bean.*;
import com.cskaoyan.wx.bo.SubmitBO;
import com.cskaoyan.wx.bo.WxOrderBO;
import com.cskaoyan.wx.bo.WxOrderCommentBO;
import com.cskaoyan.wx.vo.WxOrderDetailVO;
import com.cskaoyan.wx.vo.WxOrderVO;
import com.fasterxml.jackson.databind.exc.InvalidFormatException;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.apache.ibatis.binding.BindingException;
import org.springframework.validation.BindException;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.session.Session;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.MethodArgumentNotValidException;

import javax.xml.crypto.Data;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;

/**
 * @author： aurora
 * @data： 2021-05-12 11:06
 */
//注：已评价状态码：403
/*
    type 👉 0 : 全部      1 : 待付款      2 : 待发货       3 : 待收货         4 : 待评价

    101:未付款                              102:用户取消               103:系统取消
    201:已付款（付款功能待实现）           202:申请退款               203:已退款
    301:已发货                            401:用户收货               402:系统收货
    403：已评价

    功能显示：
    101:未付款 👉 cancel/pay : true
    102/103:取消订单 👉 delete : true
    202:申请退款 👉 全部 : false
    203:已退款 👉 delete : true
    301:已发货 👉 confirm : true
    401/402:已收货 👉 comment/delete/rebuy : true
    403：已评价👉 delete/rebuy : true
    201:已付款（付款功能待实现）

    字段：
    cancel : 取消订单     comment : 评价       confirm : 确认收货
    delete : 删除订单     pay : 付款           rebuy : 再次购买
    refund : 申请退款

 */
/*
    注意事项：
        1.根据订单状态及时更新数据库中的time字段(order表和order_goods表), 将订单删除的时候，order_goods表中的deleted标记为true
          ship_time和pay_time因功能原因暂无法更新
        2.未付款（101）状态下，半小时后系统自动取消订单
        3.已发货（301）状态下，7天后系统自动确认收货
        4.评价：一个订单对应多个商品，order的comments字段，与order_goods中comment字段相关联
        5.取消订单与删除订单：库存增加,优惠券返还（判断优惠券是否过期，设置状态码）
 */
@Service
public class WxOrderServiceImpl implements WxOrderService {

    @Autowired
    private OrderMapper orderMapper;

    @Autowired
    private OrderGoodsMapper orderGoodsMapper;

    @Autowired
    private GrouponRecordMapper grouponRecordMapper;

    @Autowired
    private CommentMapper commentMapper;

    @Autowired

    private CartMapper cartMapper;

    @Autowired
    private AddressMapper addressMapper;

    @Autowired
    private GoodsProductMapper goodsProductMapper;

    @Autowired
    private CouponUserMapper couponUserMapper;

    @Autowired
    private CouponMapper couponMapper;


    /**
     * 获取订单列表
     *
     * @param wxOrderBO
     * @return
     */
    @Override
    public WxOrderVO getOrder(WxOrderBO wxOrderBO) {
        Integer userId = UserUtils.getUserId();
        //根据showType显示具体订单信息（按照时间降序排）
        // type （list实现）👉 0:全部   1:待付款(101)    2:待发货(201)    3:待收货(301)    4:待评价(401,402)
        WxOrderVO wxOrderVO = new WxOrderVO();

        if (wxOrderBO.getShowType() == null || wxOrderBO.getShowType() == 0) {//显示全部用户订单信息

            List<WxOrder> wxOrders = orderMapper.getAllOrder(userId, false);

            return getWxOrderVO(wxOrderBO, wxOrderVO, wxOrders);
        } else {  //根据状态码显示对应订单信息
            List<Integer> type = new ArrayList<>();
            //判断状态码
            switch (wxOrderBO.getShowType()) {
                case 1:
                    type.add(101);
                    break;
                case 2:
                    type.add(201);
                    break;
                case 3:
                    type.add(301);
                    break;
                case 4:
                    type.add(401);
                    type.add(402);
                    break;
            }
            List<WxOrder> wxOrders = orderMapper.getOrderByType(userId, type, false);
            return getWxOrderVO(wxOrderBO, wxOrderVO, wxOrders);
        }
    }

    private WxOrderVO getWxOrderVO(WxOrderBO wxOrderBO, WxOrderVO wxOrderVO, List<WxOrder> wxOrders) {
        //分页
        PageHelper.startPage(wxOrderBO.getPage(), wxOrderBO.getSize());

        for (WxOrder wxOrder : wxOrders) {
            //商品：根据order_id在cskaoyanmall_order_goods中查出商品信息
            List<OrderGoodsList> orderGoodsLists = orderMapper.getOrderGoods(wxOrder.getId());
            //查询单个订单信息:根据订单id在cskaoyanmall_groupon中查询是否团购（订单id是否存在）注：逻辑删除，所以订单id不会消失
            int count = grouponRecordMapper.exitId(wxOrder.getId());
            if (count == 0) {
                wxOrder.setIsGroupin(false);
            } else
                wxOrder.setIsGroupin(true);
            //先查出状态码，根据状态码联合cskaoyanmall_order_status查出信息
            HandleOption handleOption = orderMapper.getHandleOption(wxOrder.getId());
            String orderStatusText = orderMapper.getorderStatusText(wxOrder.getId());

            wxOrder.setGoodsList(orderGoodsLists);
            wxOrder.setHandleOption(handleOption);
            wxOrder.setOrderStatusText(orderStatusText);
        }

        PageInfo<WxOrder> wxOrderPageInfo = new PageInfo<>(wxOrders);
        long count = wxOrderPageInfo.getTotal();
        int totalpages = wxOrderPageInfo.getPages();
        wxOrderVO.setData(wxOrders);
        wxOrderVO.setCount(count);
        wxOrderVO.setTotalPages(totalpages);
        return wxOrderVO;
    }


    /**
     * 获取具体订单信息
     *
     * @param orderId
     * @return
     */
    @Override
    public WxOrderDetailVO getOrderDetail(Integer orderId) {

        OrderInfo orderInfo = orderMapper.selectByPrimaryKeyWx(orderId);

        List<WxOrderGoods> wxOrderGoods = orderGoodsMapper.selectByPrimaryKeyWx(orderId);

        HandleOption handleOption = orderMapper.getHandleOption(orderId);
        String orderStatusText = orderMapper.getorderStatusText(orderId);

        orderInfo.setHandleOption(handleOption);
        orderInfo.setOrderStatusText(orderStatusText);

        WxOrderDetailVO wxOrderDetailVO = new WxOrderDetailVO();
        wxOrderDetailVO.setOrderInfo(orderInfo);
        wxOrderDetailVO.setOrderGoods(wxOrderGoods);
        return wxOrderDetailVO;
    }

    /**
     * 删除订单，逻辑删除，update_time,order_goods表中内容随之变更
     */
    @Override
    public void orderDelete(Integer orderId) {
        Date date = new Date();
        Integer count = orderMapper.orderDelete(orderId, true, date);
        orderMapper.orderGoodsDelete(orderId, true, date);
    }

    /**
     * 退款,状态码：203已退款, update_time，返回库存,更改优惠券状态码，product表中的update_time
     *
     * @param orderId
     */
    @Override
    public void orderRefund(Integer orderId) {
        Date date = new Date();
        //查询每个订单中的product_id
        List<Integer> productId = orderGoodsMapper.getProductId(orderId);
        //批量修改商品规格对应的数量以及update_time（返还库存）
        goodsProductMapper.changeNum(productId, orderId, date);
        //优惠券，一个订单只能使用一张优惠券？（永久拥有，数量不返还，只改变状态码和使用时间,update_time）,从coupon表中获取状态码
        Integer state = couponMapper.getStatus(orderId);
        couponUserMapper.changeCouponUser(orderId, state, date);
        //修改状态码
        Integer count = orderMapper.orderRefund(orderId, 203, date);
    }

    /**
     * 取消订单，状态码：102用户取消，103系统取消, update_time，end_time，返回库存，更改优惠券状态码，product表中的update_time
     * 系统自动取消，根据添加订单时间：半小时后
     *
     * @param orderId
     */
    @Override
    public void orderCancle(Integer orderId) {
        Date date = new Date();
        //查询每个订单中的product_id
        List<Integer> productId = orderGoodsMapper.getProductId(orderId);
        //批量修改商品规格对应的数量以及update_time（返还库存）
        goodsProductMapper.changeNum(productId, orderId, date);
        //优惠券，一个订单只能使用一张优惠券？（永久拥有，数量不返还，只改变状态码和使用时间,update_time）,从coupon表中获取状态码
        Integer state = couponMapper.getStatus(orderId);
        couponUserMapper.changeCouponUser(orderId, state, date);
        Integer count = orderMapper.orderCancle(orderId, 102, date);
    }

    /**
     * 确认收货，状态码：401用户收货，402系统收货, update_time，confirm_time
     * 系统自动收货，根据收货时间：7天后
     *
     * @param orderId
     */
    @Override
    public void orderConfirm(Integer orderId) {
        Date date = new Date();
        Integer count = orderMapper.orderConfirm(orderId, 401, date);
    }

    /**
     * 评价订单前获取商品
     *
     * @param orderId
     * @param goodsId
     * @return
     */
    @Override
    public WxOrderGoods getWxOrderGoods(Integer orderId, Integer goodsId) {
        WxOrderGoods wxOrderGoods = orderGoodsMapper.getWxOrderGoods(orderId, goodsId);
        return wxOrderGoods;
    }

    /**
     * 评价订单商品: order_goods表修改：comment = comment表中的id； status字段变更为403
     * comment表新增：数值；
     * order表修改：comments:待评价订单商品数量
     *
     * @param wxOrderCommentBO
     */
    @Override
    public void updateComment(WxOrderCommentBO wxOrderCommentBO) {
        Integer userId = UserUtils.getUserId();
        Date date = new Date();
        Comment comment = new Comment();
        //1.修改comment表,从order_goods中根据id获取goods_id -> 插入comment的value_id
        comment.setUserId(userId);
        comment.setContent(wxOrderCommentBO.getContent());
        comment.setHasPicture(wxOrderCommentBO.getHasPicture());
        comment.setPicUrls(wxOrderCommentBO.getPicUrls());
        comment.setStar(wxOrderCommentBO.getStar());
        comment.setType((byte) 3);//type=3，是订单商品评论
        comment.setAddTime(date);
        comment.setUpdateTime(date);
        comment.setDeleted(false);
        comment.setValueId(orderGoodsMapper.selectGoodsId(wxOrderCommentBO.getOrderGoodsId()));
        //获取id
        commentMapper.insert(comment);
        //2.修改order_goods表中comment字段：订单商品评论，如果是-1，则超期不能评价（设定7天）；如果是0，则可以评价；
        //                                  如果其他值，则是comment表里面的评论ID
        orderGoodsMapper.setComment(comment.getId(), wxOrderCommentBO.getOrderGoodsId());
        //3.修改order表:获取订单中未评价的商品数目（order_id），(修改状态码与)时间
        Integer count = orderGoodsMapper.getNoCommentNum(wxOrderCommentBO.getOrderGoodsId());
        orderMapper.updateComments(count, date, wxOrderCommentBO.getOrderGoodsId(), 403);
    }

    /**
     * 付款（逻辑实现）
     * @param orderId
     */
    @Override
    public void orderPrePay(Integer orderId) {
        Date date = new Date();
        Integer count = orderMapper.orderPrePay(orderId, 201, date);
    }


    /**
     * 购物车提交订单
     * @param submitBO
     * @return
     */
    @Override
    public Integer commit(SubmitBO submitBO) {
        //判断库存是否够   锁定库存  够继续执行  不够就报错
        // 快速付款cartId != 0;
        List<Cart> cartList = (List<Cart>) SecurityUtils.getSubject().getSession().getAttribute("checkedGoodsListBeans");

        CartExample cartExample = new CartExample();
        CartExample.Criteria criteria = cartExample.createCriteria();
        criteria.andUserIdEqualTo(UserUtils.getUserId());
        criteria.andDeletedEqualTo(false);
        //取出所有去付款的商品
        cartList = cartMapper.selectByExample(cartExample);
        //依次判断库存是否足够
        for (Cart cart : cartList) {
            int number = cart.getNumber();
            int count = cartMapper.getNumber(cart);//对应商品的库存数量
            int margin = count - number;
            if (margin < 0) {
                //库存不够就抛异常
                return -1;
            }
        }
        //库存够立马减库存
        for (Cart cart : cartList) {
            cartMapper.updateNumber(cart);
        }

        //添加部分
        //添加order表  返回的id为order  id
        Integer id = addOrder(submitBO);
        //添加order_goods表
        addOrder_goods(id);
        //将cart物理删除
        Integer cartId = submitBO.getCartId();
        if (cartId == 0) {//购物车付款情况
            cartExample.clear();
            CartExample.Criteria criteria1 = cartExample.createCriteria();
            criteria1.andUserIdEqualTo(UserUtils.getUserId());
            criteria1.andCheckedEqualTo(true);
            cartMapper.deleteByExample(cartExample);
        }
        //减优惠券  改变user_time  改变status状态
        CouponUser couponUser = new CouponUser();
        couponUser.setUserId(UserUtils.getUserId());
        couponUser.setCouponId(submitBO.getCouponId());
        couponUser.setStatus((short) 1);
        couponUser.setUsedTime(new Date());
//        orderMapper.updateGoodsNum(id,cartList,submitBO.getCouponId() );
        // 快速付款删除商品信息
        Session session = SecurityUtils.getSubject().getSession();
        session.removeAttribute("cart_" + submitBO.getCartId());
        return id;
    }

    public Integer addOrder(SubmitBO submitBO) {
        Address address = addressMapper.selectByPrimaryKey(submitBO.getAddressId());
        //遍历订单  依次往order表中塞入订单的信息
        Order order = new Order();
        //生成订单编号
        String format = getOrderId(address, order);
        order.setOrderSn(format);
        order.setOrderStatus(101);
        order.setConsignee(address.getName());
        order.setMobile(address.getMobile());
        //查询省市区
        AddressBean addressBean = orderMapper.getAddress(submitBO.getAddressId());
        order.setAddress(addressBean.getProvince() + " " + addressBean.getCity() + " " + addressBean.getArea() + " " + addressBean.getAddress());
        order.setMessage(submitBO.getMessage());
        Session session = SecurityUtils.getSubject().getSession();
        Object freightPrice = session.getAttribute("freightPrice");
        Object orderTotalPrice = session.getAttribute("orderTotalPrice");
        Object goodsTotalPrice = session.getAttribute("goodsTotalPrice");
        Object couponPrice = session.getAttribute("couponPrice");
        order.setGoodsPrice(new BigDecimal((Double) goodsTotalPrice));
        BigDecimal bigDecimal = getBigDecimal(orderTotalPrice);
        BigDecimal bigDecimal1 = getBigDecimal(freightPrice);
        BigDecimal bigDecimal2 = getBigDecimal(goodsTotalPrice);
        BigDecimal bigDecimal3 = getBigDecimal(couponPrice);
        order.setCouponPrice(bigDecimal3);
        order.setFreightPrice(bigDecimal1);
        order.setIntegralPrice(new BigDecimal(0));
        order.setGrouponPrice(new BigDecimal(0));
        order.setCouponPrice(order.getCouponPrice());
        order.setOrderPrice(bigDecimal);
        order.setActualPrice(bigDecimal);
        order.setComments((short) 0);
        order.setAddTime(new Date());
        order.setUpdateTime(new Date());
        order.setUserId(UserUtils.getUserId());
        order.setDeleted(false);
        orderMapper.insert(order);
        return order.getId();
    }


    public static BigDecimal getBigDecimal(Object value) {
        BigDecimal ret = null;
        if (value != null) {
            if (value instanceof BigDecimal) {
                ret = (BigDecimal) value;
            } else if (value instanceof String) {
                ret = new BigDecimal((String) value);
            } else if (value instanceof BigInteger) {
                ret = new BigDecimal((BigInteger) value);
            } else if (value instanceof Number) {
                ret = new BigDecimal(((Number) value).doubleValue());
            } else {
                throw new ClassCastException("Not possible to coerce [" + value + "] from class " + value.getClass() + " into a BigDecimal.");
            }
        }
        return ret;
    }


    public void addOrder_goods(Integer id) {

        List<Cart> cartList = (List<Cart>) SecurityUtils.getSubject().getSession().getAttribute("checkedGoodsListBeans");
        for (Cart cart : cartList) {
            OrderGoods orderGoods = new OrderGoods();
            orderGoods.setOrderId(id);
            orderGoods.setGoodsId(cart.getGoodsId());
            orderGoods.setGoodsSn(cart.getGoodsSn());
            orderGoods.setGoodsName(cart.getGoodsName());
            orderGoods.setProductId(cart.getProductId());
            orderGoods.setNumber(cart.getNumber().shortValue());
            orderGoods.setPrice(cart.getPrice());
            orderGoods.setSpecifications(cart.getSpecifications());
            orderGoods.setPicUrl(cart.getPicUrl());
            orderGoods.setComment(0);
            orderGoods.setAddTime(new Date());
            orderGoods.setUpdateTime(new Date());
            orderGoods.setDeleted(false);
            orderGoodsMapper.insertSelective(orderGoods);
        }
    }

    public String getOrderId(Address address, Order order) {
        Date date = new Date();
        order.setUserId(address.getUserId());
        SimpleDateFormat yyyyMMddHHmmss = new SimpleDateFormat("yyyyMMddHHmmss");
        return yyyyMMddHHmmss.format(date);
    }
}
